package org.osami.commons.dialog.dialogservice;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.*;
import org.osami.commons.deviceidentifier.IDeviceIdentifier;
import org.osami.commons.dialog.IDialogService;
import org.osami.commons.dialog.IDisplayService;


@SuppressWarnings("rawtypes")
public class DialogService implements IDialogService, EventHandler {
	
	// TODO Make public
	private final String messageEventTopic = "org/osami/commons/dialog/Message";
	private final String questionEventTopic = "org/osami/commons/dialog/Question";
	private final String userAnswerEventTopic = "org/osami/commons/dialog/UserAnswer";
	
	private BundleContext bundleContext = null;
	private EventAdmin eventAdmin = null;
	private IDisplayService display = null;
	
	private int questionCounter = 0;
	
	public EventAdmin getEventAdmin() {
		return eventAdmin;
	}
	
	private void setEventAdmin(EventAdmin eventAdmin) {
		this.eventAdmin = eventAdmin;
	}

	public IDisplayService getDisplay() {
		return display;
	}

	private void setDisplay(IDisplayService display) {
		this.display = display;
	}
	
	public BundleContext getBundleContext() {
		return bundleContext;
	}
	
	public boolean isUICapable() {
		return null != display;
	}
	
	public int generateQuestionId() {
		return questionCounter++;
	}
	
	public int createQuestion(String text, String [] options, String deviceId) {
		Dictionary properties = new Hashtable();
		String optstr = new String();
		int id = generateQuestionId();
		
		for (int i = 0; i < options.length; i++) {
			if (0 != i)
				optstr += ";";
			optstr += options[i];
		}
		
		properties.put("question", text);
		properties.put("questionId", id);
		properties.put("options", optstr);
		if(deviceId != null) {
			properties.put("deviceId", deviceId);
		}
		getEventAdmin().postEvent(new Event(questionEventTopic, properties));
		
		return id;
	}
	
	public void createMessage(String text, int type) {
		Dictionary properties = new Hashtable();
		properties.put("message", text);
		properties.put("type", type);
		properties.put("sender", getSender());
		getEventAdmin().postEvent(new Event(messageEventTopic, properties));
	}
	
	private void createAnswer(int questionId, int answerId) {
		Dictionary properties = new Hashtable();
		properties.put("questionId", questionId);
		properties.put("answerId", answerId);
		properties.put("sender", getSender());
		getEventAdmin().postEvent(new Event(userAnswerEventTopic, properties));
	}
	
	/**
	  * Event handler
	  *
	  * Handles dialog component events. If the handled event is
	  * message or question event and the current context is UI
	  * capable, DisplayService is invoked to display the message
	  * carried by the event.
	  *
	  * @param event Event to be handled
	  */
	public void handleEvent(Event event) {
		
		System.out.println("DialogService: handleEvent, Device ID: "+event.getProperty("deviceId"));
		
		if (getSender().equals((String)event.getProperty("sender"))) {
			System.out.println("Message from local instance, omitting");
			return;
		}
		
		/* Check the optional device ID. If present and different from the ID of this device, 
		 * or the ID cannot be found for this device, discard the message. If the ID is present but empty, 
		 * accept the message. */
		if((event.getProperty("deviceId") != null) && (!(event.getProperty("deviceId")).equals(""))){			
			ServiceReference deviceIdRef = getBundleContext().getServiceReference(IDeviceIdentifier.class.getName());
			if(deviceIdRef != null) {
				IDeviceIdentifier deviceId = (IDeviceIdentifier)getBundleContext().getService(deviceIdRef);
				if(deviceId.GetDeviceId().equals(event.getProperty("deviceId"))==false) {
					System.out.println("Local device ID does not match given ID => omitting message");
					return;
				}
			} else {
				System.out.println("Local device ID not found => omitting message");
				return;
			}
		}		
		
		if (!isUICapable())
			findDisplay();
		
		if (isUICapable()) { // only UI capable contexts can display dialogs
			if (messageEventTopic.equals((String)event.getProperty(EventConstants.EVENT_TOPIC))) {
				display.display((String)event.getProperty("message"), new String[0]);
			} else if (questionEventTopic.equals((String)event.getProperty(EventConstants.EVENT_TOPIC))) {
				String [] options = ((String)event.getProperty("options")).split(";");
				int answer = display.display((String)event.getProperty("question"), options);
				//JRO puukko debug
				System.out.println("Answer: "+answer+" - event.getProperty(\"questionId\"): "+event.getProperty("questionId"));
				int question = Integer.parseInt((String)event.getProperty("questionId"));
				
				createAnswer(question, answer);
				
			}
		}
	}
	
	/**
	  * Initializes the service
	  *
	  * Obtains references to OSGi eventAdmin and DisplayService if available.
	  * Registers event handlers
	  *
	  * @param context Bundle context
	  */
	public void init(BundleContext context) {
		this.bundleContext = context;
		
		ServiceReference eventAdminRef = context.getServiceReference(EventAdmin.class.getName());
        if (null != eventAdminRef) {
        	setEventAdmin((EventAdmin)context.getService(eventAdminRef));
        	//System.out.println("EventAdmin found!");
        	context.registerService(IDialogService.class.getName(), this, null);
        } else {
        	System.out.println("Warning: EventAdmin not found");
        }
        	
        
		context.registerService(EventHandler.class.getName(), this, getHandlerServiceProperties(messageEventTopic));
		context.registerService(EventHandler.class.getName(), this, getHandlerServiceProperties(questionEventTopic));
	}

	private void findDisplay() {
		ServiceReference displayRef = getBundleContext().getServiceReference(IDisplayService.class.getName());
        if (null != displayRef)
        	setDisplay((IDisplayService)getBundleContext().getService(displayRef));
	}
	
	protected Dictionary getHandlerServiceProperties(String... topics) {  
		Dictionary result = new Hashtable();  
		result.put(EventConstants.EVENT_TOPIC, topics);  
		return result;  
	}  
	
	protected Dictionary getHandlerServiceProperties(  
		String[] topics, String filter) {  
		Dictionary result = new Hashtable();  
		result.put(EventConstants.EVENT_TOPIC, topics);  
		result.put(EventConstants.EVENT_FILTER, filter);  
		return result;  
	}
	
	private String getSender() {
		try {
			return InetAddress.getLocalHost().toString();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return new String();
		}
	}
}
